home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-01-16 | 10.1 KB | 365 lines | [TEXT/ALFA] |
- ## -*-Tcl-*-
- # ###################################################################
- # Vince's Additions - an extension package for Alpha
- #
- # FILE: "cache.tcl"
- # created: 17/7/97 {3:21:07 pm}
- # last update: 16/1/1999 {2:34:09 pm}
- # Author: Vince Darley
- # E-mail: <darley@fas.harvard.edu>
- # mail: Division of Engineering and Applied Sciences, Harvard University
- # Oxford Street, Cambridge MA 02138, USA
- # www: <http://www.fas.harvard.edu/~darley/>
- #
- # Copyright (c) 1997-1998 Vince Darley, all rights reserved
- #
- # Usage:
- #
- # cache::create 'name'
- # cache::add 'name' variable var1 var2 ...
- # cache::add 'name' eval "beep" "menu Blah {}" ...
- #
- # then:
- #
- # if {[cache::exists 'name']} {
- # cache::read 'name'
- # puts "var1 = $var1, var2 = $var2"
- # puts "Also I beeped and created a menu 'Blah'"
- # }
- #
- # Alternatively, and useful when, say, you want to store lots of little
- # pieces of information, each with a different name (not really
- # associated with a particular variable, though), you can do this:
- #
- # cache::snippetWrite 'item1' value1
- # cache::snippetWrite 'item2' value2
- #
- # then:
- #
- # puts [cache::snippetRead item1]
- # puts [cache::snippetRead item2]
- #
- # This is useful if you wish to build up a large menu from lots of
- # little pieces, each of which is cached separately, because they
- # may all change individually.
- #
- # There are also procs to delete a cache, remove a snippet, or find
- # out which variables are stored in a cache.
- #
- # modified by rev reason
- # -------- --- --- -----------
- # 17/7/97 VMD 1.0 split off from filesetsMenu.tcl; improved version.
- # ###################################################################
- ##
-
- namespace eval cache {}
- # so if we make incompatible changes we can automatically delete
- # or re-interpret incompatible caches.
- set cache::version 1.0
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::exists" --
- #
- # Is there a cache with the given name
- # -------------------------------------------------------------------------
- ##
- proc cache::exists {name} {
- return [file exists [cache::name $name]]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::read" --
- #
- # Read all the information from the given cache, into the _current_
- # execution level. If you're in a proc and you want to read the
- # cache (or some of it) into global variables, you must precede
- # this call with a 'global' statement.
- #
- # If the cache doesn't exist this proc will give an error.
- # Use 'cache::exists' first to check.
- # -------------------------------------------------------------------------
- ##
- if {[info tclversion] < 8.0} {
- proc cache::read {name} {
- uplevel 1 {set cache::eval 1}
- uplevel 1 [list source [cache::name $name]]
- uplevel 1 {unset cache::eval}
- }
- } else {
- proc cache::read {name} {
- uplevel 1 {namespace eval cache {}}
- uplevel 1 {set cache::eval 1}
- uplevel 1 [list source [cache::name $name]]
- uplevel 1 {unset cache::eval}
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::readItem" --
- #
- # Read the value of a single cached item. Not very efficient. If you
- # want to do this a lot, you should think about storing 'snippets'
- # using the cache::snippetRead/Write procedures.
- # -------------------------------------------------------------------------
- ##
- proc cache::readItem {name item} {
- set cache::eval 0
- source [cache::name $name]
- return [set $item]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::variables" --
- #
- # Returns a list of the variables stored in the given cache
- # -------------------------------------------------------------------------
- ##
- proc cache::variables {name} {
- set cache::eval 0
- source [cache::name $name]
- return [lremove [info vars *] cache::eval name]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::create" --
- #
- # Write the given cache name with the given value. If any other arguments
- # are given, they are the names of other variables/arrays which should
- # also be stored.
- # -------------------------------------------------------------------------
- ##
- proc cache::create {name args} {
- close [cache::open $name create]
- if {[llength $args]} {
- uplevel 1 "cache::add [list $name] $args"
- }
- }
-
- proc cache::delete {args} {
- foreach name $args {
- if {[cache::exists $name]} {
- catch {file delete [cache::name $name]}
- }
- }
- }
-
- proc cache::deletePat {name} {
- foreach f [glob -nocomplain [cache::name $name]] {
- catch {file delete $f}
- }
- }
-
- if {[info tclversion] < 8.0} {
- proc cache::name {name} {
- global PREFS
- regsub -all "::" $name ":" name
- return "${PREFS}:Cache:${name}"
- }
- } else {
- # fix things up for cross-platform tcl 8
- proc cache::name {name} {
- global PREFS
- if {[regexp {(.*)::[^:]+} $name "" ns]} {
- # currently only allows one level of nesting
- uplevel 2 "namespace eval $ns {}"
- regsub -all "::" $name ":" name
- set name [eval file join [split $name :]]
- }
- return [file join ${PREFS} Cache ${name}]
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::add" --
- #
- # Write additional information into a pre-existing cache. The other
- # arguments are just variable names to store, if type is 'variable'.
- # Otherwise they are strings to be evaluated, if type is 'eval'.
- # -------------------------------------------------------------------------
- ##
- proc cache::add {name type args} {
- set fcache [cache::open $name append]
- switch -- $type {
- "variable" {
- foreach a $args {
- upvar $a var
- if {[array exists var]} {
- foreach n [array names var] {
- puts $fcache [list set ${a}(${n}) [set var(${n})]]
- }
- } else {
- if {[info exists var]} {
- puts $fcache [list set $a [set var]]
- }
- }
- }
- }
- "eval" {
- foreach a $args {
- puts $fcache [list if \$\{cache::eval\} [list eval $a]]
- }
- }
- }
- close $fcache
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::open" --
- #
- # You shouldn't really call this procedure. Call the others.
- # -------------------------------------------------------------------------
- ##
- proc cache::open {name {action "create"}} {
- file::ensureDirExists [file dirname [set c [cache::name $name]]]
- switch -- $action {
- "create" {
- if {[info tclversion] < 8.0} {
- set fcache [open $c w]
- } else {
- set fcache [::open $c w]
- }
- puts $fcache "# -*-Tcl-*- (nowrap)"
- global cache::version
- puts $fcache "# Cache v${cache::version} created on [mtime [now]]"
- }
- "append" {
- if {![file exists $c]} {close [cache::open $name create]}
- if {[info tclversion] < 8.0} {
- set fcache [open $c a]
- } else {
- set fcache [::open $c a]
- }
- }
- "read" {
- if {![file exists $c]} {close [cache::open $name create]}
- if {[info tclversion] < 8.0} {
- set fcache [open $c r]
- } else {
- set fcache [::open $c r]
- }
- }
- default {
- error "No such cache action '$action'"
- }
- }
- return $fcache
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::snippetWrite" --
- #
- # Store a small snippet $value, using '$name' as an identifier with
- # which to retrieve it later.
- #
- # Snippets are stored efficiently in a single file, and retrieved
- # by examining the contents of that file directly. This is
- # quicker than setting/unsetting lots of vars if you wish to
- # ask for a variety of snippets in different places in your
- # code.
- #
- # I think this proc works ok with all the weird characters, but
- # I may have missed something.
- # -------------------------------------------------------------------------
- ##
- proc cache::snippetWrite {name value {file "_snippet_"}} {
- cache::readFile $file contents
- set reg [quote::Regfind [list set _snippet_cache(${name})]]
- if {[regsub "$reg (\[^\n\]*)\n" $contents "[list set _snippet_cache(${name}) [quote::Regsub $value]]\n" contents]} {
- cache::writeFile $file contents
- } else {
- set "_snippet_cache($name)" $value
- cache::add $file "variable" _snippet_cache($name)
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::snippetRead" --
- #
- # Retrieve a previously stored snippet.
- # -------------------------------------------------------------------------
- ##
- proc cache::snippetRead {name {file "_snippet_"}} {
- cache::readFile $file contents
- set reg [quote::Regfind [list set _snippet_cache(${name})]]
- if {[regexp "$reg (\[^\n\]*)\n" $contents "" val]} {
- eval return $val
- } else {
- return ""
- }
- }
-
- proc cache::snippetRemove {name {file "_snippet_"}} {
- cache::readFile $file contents
- set reg [quote::Regfind [list set _snippet_cache(${name})]]
- if {[regsub "$reg (\[^\n\]*)\n" $contents "" contents]} {
- cache::writeFile $file contents
- }
- }
-
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::readFile" --
- #
- # Read the entire contents of a cache into the given variable
- # -------------------------------------------------------------------------
- ##
- proc cache::readFile {name contents} {
- set f [cache::name $name]
- upvar $contents c
- if {[file exists $f] && [file readable $f]} {
- if {[info tclversion] < 8.0} {
- set fileid [open $f "r"]
- set c [read $fileid]
- close $fileid
- } else {
- set fileid [::open $f "r"]
- set c [::read $fileid]
- ::close $fileid
- }
- } else {
- set c ""
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "cache::writeFile" --
- #
- # Overwrite a cache with the value of the given variable
- # -------------------------------------------------------------------------
- ##
- proc cache::writeFile {name contents} {
- upvar $contents c
- if {[info tclversion] < 8.0} {
- set fileid [open [cache::name $name] "w"]
- } else {
- set fileid [::open [cache::name $name] "w"]
- }
- puts -nonewline $fileid $c
- close $fileid
- }
-
-
-
-